/**
 * 
 */
package com.jimet.objects;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;


/**
 * @author Emre Okutan
 *
 */
public class ObjectObjectsLoader {
	/**
	 * @throws Exception 
	 * 
	 */
	private Connection conn;
	public ObjectObjectsLoader(Object objects , String[][] classesToLoad,Connection conn) throws Exception {
		this.conn = conn;
		worker(objects,classesToLoad);
	}	
	public ObjectObjectsLoader(Object objects , String[][] classesToLoad) throws Exception {
		worker(objects,classesToLoad);
	}
	
	private void worker(Object objects , String[][] classesToLoad) throws Exception {

		
		for(int s = 0;s<classesToLoad.length;s++)
		{
			String[] paramArr = classesToLoad[s];
			if(paramArr.length==2)
			{
				String[] extendArr = new String[3];
				extendArr[2] = "";
				System.arraycopy(paramArr, 0, extendArr, 0, paramArr.length);
				classesToLoad[s] = extendArr;
			}
		}
		
		Class<? extends Object> objectsClass = objects.getClass();

		Method objectsNext = null;
        Method objectsGetNext = null;
        Method objectsReset = null;
        Method objectsSize = null;
        try 
        {

        	objectsNext = objectsClass.getMethod("next", null);
        	objectsGetNext = objectsClass.getMethod("getNext", null);
        	objectsReset = objectsClass.getMethod("reset", null);
        	objectsSize = objectsClass.getMethod("size", null);
        	
        } catch(Exception ex)
        {
        	System.out.println(ex.getMessage());
        }

        if(!String.valueOf(objectsSize.invoke(objects, null)).equals("0")){
        Object inVec = null;
        while( String.valueOf(objectsNext.invoke(objects, null)).equals("true"))
        {
        	inVec = objectsGetNext.invoke(objects, null);
        	break;
        }objectsReset.invoke(objects, null);
        	
        
        
		Thread t = Thread.currentThread();
		ClassLoader cl = t.getContextClassLoader();

		//System.out.println(inVec.getClass().getName());

    	Field[] cs = inVec.getClass().getDeclaredFields();


    	
        for(int i=0;i<classesToLoad.length;i++)
        {
        	String className = "";
        	String classType = "";
        	for(int k=0;k<cs.length;k++)
        	{
        		if(classesToLoad[i][0].equals(cs[k].getName())){
        			className = cs[k].getName();
        			classType = cs[k].getType().getName();
        			break;
        		}
        	}
        	//System.out.println(className);System.out.println(makePlural(classType));
    		Class toRun = cl.loadClass(makePlural(classType));
    		Object os;
    		
    		if(classesToLoad[i][2].equals(""))
    			os = toRun.newInstance();
    		else
    			os = toRun.getConstructor( new Class[] {String.class}).newInstance(new Object[]{classesToLoad[i][2]});
    		
    		Method osLoad = null;
    		Method osNext = null;
            Method osGetNext = null;
            Method osReset = null;
            Method osSize = null;
            
    		Class partypes[] = new Class[this.conn==null?3:4];
            partypes[0] = String[].class;
            partypes[1] = String.class;
            partypes[2] = String.class;
            if(this.conn != null)
            	partypes[3] = Connection.class;
            
            try 
            {
            	if(this.conn == null)
            		osLoad = toRun.getMethod("loadByIds", partypes);
            	else
            		osLoad = toRun.getMethod("loadByIds", partypes);
            	
            	osNext = toRun.getMethod("next", null);
            	osGetNext = toRun.getMethod("getNext", null);
            	osReset = toRun.getMethod("reset", null);
            	osSize = toRun.getMethod("size", null);
            	
            } catch(Exception ex)
            {
            	System.out.println(ex.getMessage());
            }
    		String[] ids = new String[Integer.parseInt(String.valueOf(objectsSize.invoke(objects, null)))];
    		
    		int idsIndex=0;
            while( String.valueOf(objectsNext.invoke(objects, null)).equals("true"))
            {
            	String getIdStr = "get" + getFirstCaseUpper( classesToLoad[i][1] );
            	
            	Object o = objectsGetNext.invoke(objects, null);

            	Method getId = o.getClass().getMethod(getIdStr, null);

            	if(String.valueOf(getId.invoke(o, null)).equals("-1"))
            	{
            		Class toRun1 = cl.loadClass(classType);
            		Object obNew;
            		
            		if(classesToLoad[i][2].equals(""))
            			obNew = toRun1.newInstance();
            		else
            			obNew = toRun1.getConstructor( new Class[] {String.class}).newInstance(new Object[]{classesToLoad[i][2]});

            		
            		Method setOb = o.getClass().getMethod("set" + getFirstCaseUpper( className ) , new Class[]{obNew.getClass()});
            		
            		setOb.invoke(o, new Object[]{obNew});
             	
            	}

            	
            	
            	ids[idsIndex] = String.valueOf(getId.invoke(o, null));
            	
            	
            	idsIndex++;
            }objectsReset.invoke(objects, null);
            
            if(this.conn==null)
            osLoad.invoke(os, new Object[] { ids , "ASC" , "id" });
            else
            	osLoad.invoke(os, new Object[] { ids , "ASC" , "id" ,this.conn});
            //System.out.println(osSize.invoke(os, null));
    		
            while( String.valueOf(osNext.invoke(os, null)).equals("true"))
            {
            	String getIdStr = "get" + getFirstCaseUpper( classesToLoad[i][1] );
            	
            	Object o = osGetNext.invoke(os, null);
            	Method getId = o.getClass().getMethod("getId", null);

            
                while( String.valueOf(objectsNext.invoke(objects, null)).equals("true"))
                {
                	Object oInner = objectsGetNext.invoke(objects, null);
                	Method getoInnerId = oInner.getClass().getMethod(getIdStr, null);
                	

                	if(Integer.parseInt(String.valueOf(getId.invoke(o, null))) == Integer.parseInt(String.valueOf(getoInnerId.invoke(oInner, null))))
                	{
                		
                		Class partype[] = new Class[1];
                        partype[0] = o.getClass();
                        
                		Method objectSetter = oInner.getClass().getMethod("set" + getFirstCaseUpper( classesToLoad[i][0]), partype);
                		objectSetter.invoke(oInner, new Object[] { o });
                		//break;
                	}
                	
                	
                }objectsReset.invoke(objects, null);
                
                while( String.valueOf(objectsNext.invoke(objects, null)).equals("true"))
                {
                	Object oInner = objectsGetNext.invoke(objects, null);
                   
            		Method objectGetter = oInner.getClass().getMethod("get" + getFirstCaseUpper( classesToLoad[i][0]), null);
            		Object retVal = objectGetter.invoke(oInner, null);
                	if(retVal==null)
                	{
                		Class newObClass = cl.loadClass(classType);
                		Object newOb;
                		
                		if(classesToLoad[i][2].equals(""))
                			newOb = newObClass.newInstance();
                		else
                			newOb = newObClass.getConstructor( new Class[] {String.class}).newInstance(new Object[]{classesToLoad[i][2]});

                		
                		Class partype[] = new Class[1];
                        partype[0] = newOb.getClass();
                        
                		Method objectSetter = oInner.getClass().getMethod("set" + getFirstCaseUpper( classesToLoad[i][0]), partype);
                		objectSetter.invoke(oInner, new Object[] { newOb });
                	}
                	
                }objectsReset.invoke(objects, null);

            }osReset.invoke(os, null);
            
        }
        }
			
		
	}
	//a�a��daki iki method kullan�lan nesneler velocity ile �retilirken o 
	//velocitynin templateUtil nesnesinde nas�l ise ayn� ola...
	public String makePlural(String strTemp)
	{
			if(strTemp.endsWith("y")){
				return strTemp.substring(0,strTemp.length()-1) + "ies";
			}
			else if(strTemp.endsWith("s")){
				return strTemp+"es";
			}
			else
			{
				return strTemp+"s";
			}

	}
	
	public String getFirstCaseUpper(String strTemp){
		String strFirstCase = strTemp.substring(0, 1);
		String strOther = strTemp.substring(1, strTemp.length());
		String strUpperCase = strFirstCase.toUpperCase();
		//Added for Turkish character set compatibility.
		if(strUpperCase.equals("") || strUpperCase.equals("İ"))
			strUpperCase = "I";
		
		return strUpperCase + strOther;
	}
}
